package entutil

import (
	"bytes"
	"entgo.io/ent/entc/gen"
	"entgo.io/ent/schema"
	"fmt"
	"os"
	"path/filepath"
	"text/template"
)

type (
	genTemplates []genTemplate
	genTemplate  map[string]any
	GenType      struct {
		*gen.Type
		Data genTemplate
	}
)

func NewTemplates(tmps ...genTemplate) schema.Annotation {
	return genTemplates(tmps)
}
func (t genTemplates) Name() string {
	return "templates"
}
func NewTemplate(file string, out string) genTemplate {
	return genTemplate{
		"_file":  file,
		"_out":   out,
		"_cover": false,
	}
}
func (t genTemplate) Cover() genTemplate {
	t["_cover"] = true
	return t
}
func (t genTemplate) Data(data map[string]any) genTemplate {
	for k, v := range data {
		t[k] = v
	}
	return t
}
func (t genTemplate) render(typ *gen.Type) error {
	out := t["_out"].(string)
	tmpFile := t["_file"].(string)
	renderData := GenType{Type: typ, Data: t}
	if !t["_cover"].(bool) {
		_, err := os.Stat(out)
		if err == nil {
			return nil
		}
	}
	tmp, err := template.New(tmpFile).ParseFiles(tmpFile)
	if err != nil {
		return fmt.Errorf("entutil: template parse file %s: %w", tmpFile, err)
	}
	var buf bytes.Buffer
	if err = tmp.Execute(&buf, renderData); err != nil {
		return fmt.Errorf("entutil: template execute: %w", err)
	}
	os.MkdirAll(filepath.Dir(out), 0755)
	if err = os.WriteFile(out, buf.Bytes(), 0777); err != nil {
		return fmt.Errorf("entutil: write template file %s: %w", out, err)
	}
	return nil
}
